<?php
    class PageInfoByURLFinder
    {
        /**
         * @var array
         */
        private $matchedPages;
        /**
         * @var array
         */
        private $similarPages;

        public function __construct()
        {
            $this->matchedPages = array();
            $this->similarPages = array();
        }

        /**
         * @param string $url
         * @return PageInfo
         */
        public function Find( $url )
        {
            $this->FindMatches( $url );

            foreach (SiteLanguage::GetAdditionalLanguagesList() as $lng)
            {
                $pageInfo = $this->GetFoundMatchByLanguage( $lng );
                if (!is_null($pageInfo))
                {
                    break;
                }
            }

            if ( is_null( $pageInfo ) )
            {
                $pageInfo = $this->GetFoundMatchByLanguage( SiteLanguage::EN );
            }
            if ( is_null($pageInfo) )
            {
                $pageInfo = $this->GetFoundSimilarPage( $url );
            }

            return $pageInfo;
        }


        /**
         * Finds pages with similar url and parameters.
         * Saves found matched and similar pages data into $matchedPages and $similarPages.
         * @param sting $url
         */
        private function FindMatches( $url )
        {
            UrlHelper::SplitParams($url, $path, $params);
            $path = ltrim( $path, '/' );
            $requestParamsCount = count($params);

            $urls = Core::ResourceManager()->GetUrls();
            $similarPages = array();
            $matchedPages = array();

            foreach ( $urls as $pageId => $pageUrl )
            {
                UrlHelper::SplitParams( $pageUrl, $pagePath, $pageParams );
                if ( $path == $pagePath )
                {
                    $paramsCount = count($pageParams);
                    $matched = false;
                    if ( $requestParamsCount == $paramsCount )
                    {
                        $matched = true;
                        foreach ($params as $requestParam => $value)
                        {
                            // all parameters must match
                            if ( !isset($pageParams[$requestParam]) || $pageParams[$requestParam] != $value )
                            {
                                $matched = false;
                                break;
                            }
                        }
                    }

                    if ($matched)
                    {
                        $matchedPages[] = $pageId;
                    }
                    else
                    {
                        $similarPages[$pageId] = $pageUrl;
                    }
                }
            }
            $this->similarPages = $similarPages;
            $this->matchedPages = $matchedPages;
        }

        /**
         * Returns found matched page info for specified language.
         * @param string $language
         * @return PageInfo
         */
        private function GetFoundMatchByLanguage( $language )
        {
            $foundPageInfo = null;
            if ( count( $this->matchedPages ) > 0 )
            {
                foreach( $this->matchedPages as $matchPage )
                {
                    $pageInfo = Pages::GetPageInfo( $matchPage );
                    if ( $pageInfo->language == $language )
                    {
                        $foundPageInfo = $pageInfo;
                        break;
                    }
                }
            }
            return $foundPageInfo;
        }

        /**
         * Returns found similar page info.
         * @param string $url
         * @return PageInfo
         */
        private function GetFoundSimilarPage( $url )
        {
            $pageInfo = null;

            // Some similar pages found
            // Returning first site map page with maximum number of matching parameters
            $paramsMax = -1; //To use first similar script if needed
            if ( count( $this->similarPages ) > 0 )
            {
                $page = "";
                foreach ( $this->similarPages as $pageId => $pageUrl )
                {
                    $paramsMatched = UrlHelper::ParamsMatched( $url, $pageUrl );
                    if ( $paramsMatched > $paramsMax )
                    {
                        $paramsMax  = $paramsMatched;
                        $page = $pageId;
                    }
                }
                if ( !empty( $page ) )
                {
                    $pageInfo = Pages::GetPageInfo( $page );
                }
            }

            return $pageInfo;
        }
    }
?>